#include "StdAfx.h"
#include "PipingListener.h"

using namespace VisualGTest::Message;

PipingListener::PipingListener(void) :
    m_hNamedPipe(NULL)
{
}

PipingListener::PipingListener(HANDLE hNamedPipe) :
    m_hNamedPipe(hNamedPipe)
{
}

PipingListener::~PipingListener(void)
{
}

void PipingListener::OnTestProgramStart(const testing::UnitTest& unit_test)
{
    bool ok = PipeEvent(Event_EventType_TestProgramStart,
        Event_PayloadType_UNIT_TEST, msgFactory.Create(unit_test));
}

void PipingListener::OnTestIterationStart(const testing::UnitTest& unit_test,
                                  int iteration)
{
    // TODO - do we need to pass on the value of iteration too?
    bool ok = PipeEvent(Event_EventType_TestIterationStart,
        Event_PayloadType_UNIT_TEST, msgFactory.Create(unit_test));
}

void PipingListener::OnEnvironmentsSetUpStart(const testing::UnitTest& unit_test)
{
    bool ok = PipeEvent(Event_EventType_EnvironmentsSetUpStart,
        Event_PayloadType_UNIT_TEST, msgFactory.Create(unit_test));
}

void PipingListener::OnEnvironmentsSetUpEnd(const testing::UnitTest& unit_test)
{
    bool ok = PipeEvent(Event_EventType_EnvironmentsSetUpEnd,
        Event_PayloadType_UNIT_TEST, msgFactory.Create(unit_test));
}

void PipingListener::OnTestCaseStart(const testing::TestCase& test_case)
{
    bool ok = PipeEvent(Event_EventType_TestCaseStart,
        Event_PayloadType_TEST_CASE, msgFactory.Create(test_case));
}

void PipingListener::OnTestStart(const testing::TestInfo& test_info)
{
    bool ok = PipeEvent(Event_EventType_TestStart,
        Event_PayloadType_TEST_INFO, msgFactory.Create(test_info));
}

void PipingListener::OnTestPartResult(const testing::TestPartResult& test_part_result)
{
    bool ok = PipeEvent(Event_EventType_TestPartResult,
        Event_PayloadType_TEST_PART_RESULT, msgFactory.Create(test_part_result));
}

void PipingListener::OnTestEnd(const testing::TestInfo& test_info)
{
    bool ok = PipeEvent(Event_EventType_TestEnd,
        Event_PayloadType_TEST_INFO, msgFactory.Create(test_info));
}

void PipingListener::OnTestCaseEnd(const testing::TestCase& test_case)
{
    bool ok = PipeEvent(Event_EventType_TestCaseEnd,
        Event_PayloadType_TEST_CASE, msgFactory.Create(test_case));
}

void PipingListener::OnEnvironmentsTearDownStart(const testing::UnitTest& unit_test)
{
    bool ok = PipeEvent(Event_EventType_EnvironmentsTearDownStart,
        Event_PayloadType_UNIT_TEST, msgFactory.Create(unit_test));
}

void PipingListener::OnEnvironmentsTearDownEnd(const testing::UnitTest& unit_test)
{
    bool ok = PipeEvent(Event_EventType_EnvironmentsTearDownEnd,
        Event_PayloadType_UNIT_TEST, msgFactory.Create(unit_test));
}

void PipingListener::OnTestIterationEnd(const testing::UnitTest& unit_test,
                                int iteration)
{
    bool ok = PipeEvent(Event_EventType_TestIterationEnd,
        Event_PayloadType_UNIT_TEST, msgFactory.Create(unit_test));
}

void PipingListener::OnTestProgramEnd(const testing::UnitTest& unit_test)
{
    bool ok = PipeEvent(Event_EventType_TestProgramEnd,
        Event_PayloadType_UNIT_TEST, msgFactory.Create(unit_test));
}

// operations //

void PipingListener::SetPipe(HANDLE hNamedPipe)
{
    m_hNamedPipe = hNamedPipe;
}

HANDLE PipingListener::GetPipe() const
{
    return m_hNamedPipe;
}

bool PipingListener::PipeMessage(const google::protobuf::Message& msg)
{
    std::string serializedMsg = msg.SerializeAsString();
    DWORD numberOfBytesWritten;

    if (m_hNamedPipe) {
        // write the message itself
        int result = WriteFile(
            m_hNamedPipe,
            serializedMsg.c_str(),
            static_cast<DWORD>(serializedMsg.size()),
            &numberOfBytesWritten,
            NULL
        );

        return (result != 0);
    }

    return false;
}

bool PipingListener::PipeEvent(Event_EventType eventType, Event_PayloadType payloadType,
                               const google::protobuf::Message& payload)
{
    Event event;

    event.set_eventtype(eventType);
    event.set_payloadtype(payloadType);

    switch (payloadType) {
        case Event_PayloadType_UNIT_TEST:
            event.mutable_unittest()->CopyFrom(payload);
            break;

        case Event_PayloadType_TEST_CASE:
            event.mutable_testcase()->CopyFrom(payload);
            break;

        case Event_PayloadType_TEST_INFO:
            event.mutable_testinfo()->CopyFrom(payload);
            break;

        case Event_PayloadType_TEST_PART_RESULT:
            event.mutable_testpartresult()->CopyFrom(payload);
            break;
    }

    return PipeMessage(event);
}
